/*
trait，这是一个定义泛型行为的方法。trait 可以与泛型结合来将泛型限制为拥有特定行为的类型，而不是任意类型。
生命周期（lifetimes），它是一类允许我们向编译器提供引用如何相互关联的泛型。
Rust 的生命周期功能允许在很多场景下借用值的同时仍然使编译器能够检查这些引用的有效性。
*/


/// 泛型
fn largest<T>(list: &[T]) -> T {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}



struct Point<T, U> {
    x: T,
    y: U,
}
impl<T, U> Point<T, U> {
    fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
        Point {
            x: self.x,
            y: other.y,
        }
    }
}

enum Option<T> {
    Some(T),
    None,
}

enum Result<T, E> {
    Ok(T),
    Err(E),
}


fn main() {
    let number_list = vec![34, 50, 25, 100, 65];
    let result = largest(&number_list);
    println!("The largest number is {}", result);

    let char_list = vec!['y', 'm', 'a', 'q'];
    let result = largest(&char_list);
    println!("The largest char is {}", result);

    let integer = Point { x: 5, y: 10 };
    let float = Point { x: 1.0, y: 4.0 };
}


/// trait：定义共享的行为
// trait 类似于其他语言中常被称为 接口（interfaces）的功能
fn main() {
    pub trait Summary {
        fn summarize(&self) -> String;

        // 默认实现
        // 有时为 trait 中的某些或全部方法提供默认的行为，而不是在每个类型的每个实现中都定义自己的行为是很有用的。
        // 这样当为某个特定类型实现 trait 时，可以选择保留或重载每个方法的默认行为。
        fn default_summarize(&self) -> String {
            // 默认实现允许调用相同 trait 中的其他方法，哪怕这些方法没有默认实现。
            format!("(Read more from {}...)", self.summarize());
            String::from("(Read more...)")
        }
    }

    pub struct NewsArticle {
        pub headline: String,
        pub location: String,
        pub author: String,
        pub content: String,
    }

    // 为类型实现 trait
    impl Summary for NewsArticle {
        fn summarize(&self) -> String {
            format!("{}, by {} ({})", self.headline, self.author, self.location)
        }
    }

    pub struct Tweet {
        pub username: String,
        pub content: String,
        pub reply: bool,
        pub retweet: bool,
    }

    impl Summary for Tweet {
        fn summarize(&self) -> String {
            format!("{}: {}", self.username, self.content)
        }
    }

    let tweet = Tweet {
        username: String::from("horse_ebooks"),
        content: String::from("of course, as you probably already know, people"),
        reply: false,
        retweet: false,
    };
    // 一旦实现了 trait，我们就可以用与 NewsArticle 和 Tweet 实例的非 trait 方法一样的方式调用 trait 方法了
    println!("1 new tweet: {}", tweet.summarize());

}


/// 生命周期与引用有效性
/*
Rust 中的每一个引用都有其 生命周期（lifetime），也就是引用保持有效的作用域。
大部分时候生命周期是隐含并可以推断的，正如大部分时候类型也是可以推断的一样。
类似于当因为有多种可能类型的时候不得不注明类型，也会出现引用的生命周期以一些不同方式相关联的情况，
所以 Rust 需要我们使用泛型生命周期参数来注明他们的关系，这样就能确保运行时实际使用的引用绝对是有效的。
*/
/// 生命周期避免了悬垂引用
// 生命周期的主要目标是避免悬垂引用，它会导致程序引用了非预期引用的数据。
/// Rust 编译器有一个 借用检查器（borrow checker），它比较作用域来确保所有的借用都是有效的
fn demo() {
    // 变量在使用之前必须被初始化
    let r;          // ---------+-- 'a
    {                     //          |
        let x = 5;   // -+-- 'b  |
        r = &x;           //  |       |
    }                     // -+       |
    println!("r: {}", r); //          |
}                         // ---------+
// 这里将 r 的生命周期标记为 'a 并将 x 的生命周期标记为 'b。如你所见，内部的 'b 块要比外部的生命周期
// 'a 小得多。在编译时，Rust 比较这两个生命周期的大小，并发现 r 拥有生命周期 'a，
// 不过它引用了一个拥有生命周期 'b 的对象。程序被拒绝编译，因为生命周期 'b 比生命周期 'a 要小
// 被引用的对象比它的引用者存在的时间更短。


// 函数签名中的生命周期标注
fn main() {

    // &i32        // 引用
    // &'a i32     // 带有显式生命周期的引用
    // &'a mut i32 // 带有显式生命周期的可变引用

    /// 编译不通过
    fn longest(x: &str, y: &str) -> &str {
        if x.len() > y.len() {
            x
        } else {
            y
        }
    }

    /// 生命周期整改， 泛型生命周期参数 'a 'b 等
    // 这里我们想要告诉 Rust 关于参数中的引用和返回值之间的限制是他们都必须拥有相同的生命周期
    fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
        if x.len() > y.len() {
            x
        } else {
            y
        }
    }
}
// 提示文本揭示了返回值需要一个泛型生命周期参数，因为 Rust 并不知道将要返回的引用是指向 x 或 y。
// 事实上我们也不知道，因为函数体中 if 块返回一个 x 的引用而 else 块返回一个 y 的引用！
// 当我们定义这个函数的时候，并不知道传递给函数的具体值，所以也不知道到底是 if 还是 else 会被执行。
// 我们也不知道传入的引用的具体生命周期



/// 泛型生命周期参数说明
/// 当然可以。下面我将通过一个示例来展示为什么在`longest`函数中使用泛型生命周期参数是必要的：
struct Example<'a> {
    longest_str: &'a str,
}

impl<'a> Example<'a> {
    // Self 代表 Example 结构体自身
    fn new(x: &'a str, y: &'a str) -> Self {
        Example {
            longest_str: longest(x, y),
        }
    }
}

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let s1 = String::from("hello");
    let s2 = String::from("world");

    // 这里创建了一个临时字符串 "rust" 和 "ace"
    let _temp1 = "rust";
    let _temp2 = "ace";

    let e = Example::new(&s1, &_temp1); // 错误：_temp1 的生命周期太短
    let f = Example::new(&s2, &_temp2); // 错误：_temp2 的生命周期太短

    let g = Example::new(&s1, &s2); // 正确：s1 和 s2 的生命周期足够长
}


/*
在这个例子中，我们定义了一个结构体`Example`，它包含一个字段`longest_str`，该字段存储通过调用`longest`函数得到的最长字符串的引用。
当尝试创建`Example`实例时，如果其中一个参数是局部变量或者生命周期比结构体本身短的引用（如`_temp1`和`_temp2`），则会触发编译错误。这是因为`Example`的生命周期比`_temp1`或`_temp2`长，而`longest_str`字段保存的引用必须在其整个生命周期内都是有效的。
然而，当我们使用`&s1`和`&s2`作为参数时，没有问题，因为`s1`和`s2`的生命周期足够长，它们至少会持续到`main`函数结束。因此，`Example::new(&s1, &s2)`能够成功创建一个`Example`实例。
这就是为什么我们需要在`longest`函数中使用泛型生命周期参数`'a`，以确保返回的引用在函数外部仍然有效，并且与传递给它的引用有相容的生命周期。
 */

/// 静态生命周期
// 这里有一种特殊的生命周期值得讨论：'static，其生命周期能够存活于整个程序期间。所有的字符串字面量都拥有 'static 生命周期
fn main() {
    let s: &'static str = "I have a static lifetime.";
}
